/**
 * Copyright (C) 2014
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package psn.shan.xml.enhancedvalidator.rules;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;

import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.filter.Filters;
import org.jdom2.xpath.XPathBuilder;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;

/**
 * AbstractLinkedRule <br />
 * 
 * Base for linked rules where validation is dependent on one or more set of nodes relative to current node.
 * References are specified by XPath expressions.  
 * Design does not restrict to XPath 1.0 but implementation uses JDOM 2 which may not allow full XPath 2.0 API.
 * Design allows for multiple references each returning multiple matches.
 * Design is restrictive with only references resulting in Element matches working.  
 * 
 * @author Shan
 * 
 */
@Accessors(prefix = "m")
@EqualsAndHashCode(callSuper=true)
@ToString(includeFieldNames=true, callSuper=true)
public abstract class AbstractLinkedRule extends AbstractBaseRule {
	@Getter @Setter
	private List<String> mReferences = null;

	protected static String REFERENCE_VARIABLE = "$Ref$";
	
	private Map<String, XPathExpression<Element>> mReferenceXPs = null;
	
	public AbstractLinkedRule() {
		mReferences = new Vector<>();
		mReferenceXPs = new HashMap<>();
	}
	
	protected List<List<Element>> getReferredElements(Element aInput) {
		List<List<Element>> lReferredElements = new Vector<>();
		for (String lLinkedTo : mReferences) {
			XPathExpression<Element> lLinkedExpression = mReferenceXPs.get(lLinkedTo);
			List<Element> lReferences = lLinkedExpression.evaluate(aInput);
			
			lReferredElements.add(lReferences);
		}
		return lReferredElements;
	}
	
	public void setupRule(Collection<Namespace> aRuleverse) {
		super.setupRule(aRuleverse);
		
		XPathFactory lXPathFactory = XPathFactory.instance();
		
		for (String lReference : mReferences) {
			XPathBuilder<Element> lXPathBuilder = new XPathBuilder<Element>(lReference, Filters.element());
			lXPathBuilder.setNamespaces(aRuleverse);
			
			mReferenceXPs.put(lReference, lXPathBuilder.compileWith(lXPathFactory));
		}
	}	
}
